/*
 * This file is part of LazyCipher. LazyCipher is free software: you can
 * redistribute it and/or modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version. LazyCipher is distributed in
 * the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
 * the GNU General Public License for more details. You should have received a
 * copy of the GNU General Public License along with LazyCipher. If not, see
 * <http://www.gnu.org/licenses/>.
 */
package org.lazycoder.Crypto;

import java.util.Vector;

/**
 * A representation of letters. This isn't the same as a character, characters
 * are integers that refer to a symbol in UTF. A letter is a construct with a
 * charset (a list of symbols typically a-z) and an index which shows which
 * letter is being referred to.
 * 
 * @author Matthew Bayliss
 */
public class Letter {
	/** The charset to be used (typically a-z). */
	private final Vector<Character>	charset;
	/** The letter being refered to. */
	private Integer					index;
	/**
	 * The original symbol. This is only really useful for symbols which will
	 * return this instead of anything else but i'm thinking it shouldn't be
	 * stored for other letters (it could be used to grab the original value of
	 * the letter)
	 */
	private char					original;

	/**
	 * Create a letter and set the charset
	 * 
	 * @param CharSet
	 *            a list of characters
	 * @param index
	 *            the index of the selected letter
	 */
	private Letter(Vector<Character> CharSet, Integer index) {
		this.charset = CharSet;
		this.index = index;
	}

	/**
	 * Create a letter and set the charset
	 * 
	 * @param CharSet
	 *            a list of characters
	 * @param index
	 *            the index of the selected letter
	 */
	private Letter(Vector<Character> CharSet, char index) {
		this.charset = CharSet;
		original = index;

		index = Character.toUpperCase(index);
		if (Character.isAlphabetic(index)) {
			this.index = charset.indexOf(index);
		} else {
			this.index = -1;
		}
	}

	/**
	 * Selects a letter in the latin charset.
	 * 
	 * @param index
	 *            The index of the letter. A = 0, B = 1, etc
	 * @return a new letter.
	 */
	public static Letter createLatinLetter(char symbol) {
		Letter letter = null;
		String charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
		Vector<Character> cs = cToVector(charset.toCharArray());
		letter = new Letter(cs, symbol);
		return letter;
	}

	/**
	 * Selects a letter in the latin charset.
	 * 
	 * @param index
	 *            The index of the letter. A = 0, B = 1, etc
	 * @return a new letter.
	 */
	public static Letter createLatinLetter(int symbol) {
		Letter letter = null;
		String charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
		Vector<Character> cs = cToVector(charset.toCharArray());
		letter = new Letter(cs, symbol);
		return letter;
	}

	/**
	 * @return the currently selected character
	 */
	public char getValue() {
		if (Character.isUpperCase(original)) {
			return Character.toUpperCase(charset.get(index));
		} else if (Character.isLowerCase(original)) {
			return Character.toLowerCase(charset.get(index));
		} else {
			return original;
		}
	}

	/**
	 * @return the current index
	 */
	public int getIndex() {
		return index;
	}

	/**
	 * Adds the value parameter to the index then ensures it is within the
	 * charset range (using modulo)
	 * 
	 * @param value
	 *            the amount to increase the index by
	 */
	public void add(Integer value) {
		index += value;
		if (value < charset.size()) {
			index %= charset.size();
		}
	}

	/**
	 * subtracts the value parameter to the index then ensures it is within the
	 * charset range (using modulo)
	 * 
	 * @param value
	 *            the amount to decrese the index by
	 */
	public void sub(Integer value) {
		index += charset.size() - value;
		if (value < charset.size()) {
			index %= charset.size();
		}
	}

	/**
	 * Adds the value parameter to the index then ensures it is within the
	 * charset range (using modulo)
	 * 
	 * @param value
	 *            the amount to increase the index by
	 */
	public void add(Letter value) {
		index += value.getIndex();
		index %= charset.size();
	}

	/**
	 * subtracts the value parameter to the index then ensures it is within the
	 * charset range (using modulo)
	 * 
	 * @param value
	 *            the amount to decrese the index by
	 */
	public void sub(Letter value) {
		index += charset.size() - value.getIndex();
		index %= charset.size();
	}

	public boolean isAlphabetic() {
		if (Character.isAlphabetic(original)) {
			return true;
		} else {
			return false;
		}
	}

	@Override
	public String toString() {
		return String.valueOf(getValue());
	}

	private static Vector<Character> cToVector(char[] c) {
		Vector<Character> cs = new Vector<Character>();
		for (char ch : c) {
			cs.add(ch);
		}
		return cs;
	}
}
